Skip to content

Allow SV_PrimitiveID in ray tracing hit stages#11423

Open
jkwak-work wants to merge 62 commits into
shader-slang:masterfrom
jkwak-work:issue-11197
Open

Allow SV_PrimitiveID in ray tracing hit stages#11423
jkwak-work wants to merge 62 commits into
shader-slang:masterfrom
jkwak-work:issue-11197

Conversation

@jkwak-work

@jkwak-work jkwak-work commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes #11197

Summary of the problem from the end user perspective

SV_PrimitiveID could not be used consistently as an input in ray tracing intersection, any-hit, and closest-hit shaders. Shaders that need the primitive index in those stages had to use backend-specific forms instead of the semantic spelling.

Minimal repro shader; if applicable

[shader("closesthit")]
void main(uint primitiveId : SV_PrimitiveID)
{
    uint id = primitiveId;
}

Root cause

The semantic metadata and parameter binding rules did not allow SV_PrimitiveID in ray tracing hit stages. Backend legalization also needed target-specific handling so the value is not treated like payload or hit-attribute data.

Solution in this PR

The PR allows SV_PrimitiveID in intersection, any-hit, and closest-hit stages. SPIR-V lowers it as BuiltIn PrimitiveId input, SPIR-V-via-GLSL routes through gl_PrimitiveID, HLSL/DXIL emission replaces uses with the native PrimitiveIndex() intrinsic, and CUDA/OptiX emission replaces uses with optixGetPrimitiveIndex().

Notes to the reviewers; where to focus on

The main review points are the semantic/stage allowlist changes, the parameter-binding behavior for ray tracing system-value inputs, and the SPIR-V, GLSL, HLSL, and CUDA legalization paths. Direct SPIR-V ray tracing entry points still reach the GLSL legalization pass, so the shouldEmitSPIRVDirectly() guard in that pass is intentional.

Reviewer Directives (maintained by agent)

Related PRs in the past

@jkwak-work jkwak-work added pr: non-breaking PRs without breaking changes CoPilot labels Jun 2, 2026
@jkwak-work jkwak-work self-assigned this Jun 2, 2026
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds SV_PrimitiveID hit-stage support across semantics, parameter binding, IR legalization, backend emit paths (HLSL/GLSL/SPIR‑V/CUDA), and extensive regression/diagnostic tests.

Changes

SV_PrimitiveID ray tracing hit-stage support

Layer / File(s) Summary
Semantic declaration and stage requirements
source/slang/core.meta.slang
sv_primitiveid accessor now lists intersection, anyhit, and closesthit as allowed stages.
Parameter validation and binding
source/slang/slang-parameter-binding.cpp
Adds allowlist detection for runtime-provided SV_PrimitiveID on hit stages, target gating (D3D/Khronos/CUDA), suppresses some stage-rejection diagnostics, and avoids treating allowed inputs as hit-attributes.
Varying-parameter legalization core
source/slang/slang-ir-legalize-varying-params.{h,cpp}
Adds isRayTracingHitStage, tryLegalizeRayTracingPrimitiveIDParam/...StructParam, virtualized entry-point/param hooks, entry-point filtering, core primitive-ID detection/rewriting, HLSL driver legalizeRayTracingPrimitiveIDParamsForHLSL, and CUDA signature/system-value adjustments.
HLSL legalization wiring
source/slang/slang-ir-hlsl-legalize.{h,cpp}
Replaces legalizeNonStructParameterToStructForHLSL with legalizeParametersForHLSL, iterates functions to force-temp-structs, and invokes primitive-ID legalization.
Emit flow and SPIR‑V address-space inference
source/slang/slang-emit.cpp, source/slang/slang-ir-spirv-legalize.cpp
D3D emit path calls new HLSL pass; SPIR‑V address-space inference maps hit-stage sv_primitiveid to AddressSpace::BuiltinInput when appropriate.
GLSL legalization & direct-SPIRV emitter
source/slang/slang-ir-glsl-legalize.cpp
Adds optional pre-consolidation primitive-ID canonicalization, a direct-SPIRV primitive-ID emitter, and rewrites param traversal to allow removal during consolidation.
Pipeline intrinsic tests
tests/hlsl-intrinsic/ray-tracing/rt-pipeline-intrinsics-*.slang
Adds any-hit/closest-hit/intersection entry points and FileCheck assertions validating SPIR‑V PrimitiveId and DXIL primitiveIndex/reportHit usage for uint/int/unused variants.
Cross-backend regression matrix
tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang
Adds a comprehensive matrix covering lowering to DXIL/GLSL/SPIR‑V/CUDA, name-collision, forwarding, inout mutation, and struct/nested/mixed variants.
CUDA tests
tests/cuda/sv-primitiveid-raytracing.slang
Asserts CUDA lowering uses optixGetPrimitiveIndex() and omits primitiveID parameter forms, including int→float helper usage.
Diagnostic regression coverage
tests/diagnostics/execution-model/sv-primitiveid-rt-invalid.slang
Adds diagnostics covering disallowed stages/directions, unsupported targets, and wrong carrier types for SV_PrimitiveID.

Suggested reviewers

  • bmillsNV
  • mkeshavaNV
  • csyonghe
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Allow SV_PrimitiveID in ray tracing hit stages' accurately and specifically describes the main change: enabling SV_PrimitiveID as a valid semantic in ray tracing hit-stage shaders (intersection, any-hit, closest-hit).
Description check ✅ Passed The PR description is comprehensive and directly related to the changeset. It explains the problem, root cause, solution approach, and implementation details across multiple backends (SPIR-V, GLSL, HLSL, CUDA).
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from issue #11197: accepts SV_PrimitiveID in hit stages, fixes compilation failures, ensures correct primitive index values, and provides consistent backend behavior (SPIR-V direct, SPIR-V via GLSL, HLSL/DXIL, CUDA/OptiX).
Out of Scope Changes check ✅ Passed All changes are directly aligned with the PR objectives. Core semantic allowlist changes, parameter binding, and backend legalization paths (SPIR-V, GLSL, HLSL, CUDA) are in scope. Comprehensive test coverage validates the implementation across multiple backends and edge cases.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jkwak-work

This comment has been minimized.

@coderabbitai

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ba7eab78-0f00-444e-ad98-ede136284665

📥 Commits

Reviewing files that changed from the base of the PR and between fd4f6c7 and b85c65b.

📒 Files selected for processing (11)
  • source/slang/core.meta.slang
  • source/slang/slang-emit.cpp
  • source/slang/slang-ir-glsl-legalize.cpp
  • source/slang/slang-ir-hlsl-legalize.cpp
  • source/slang/slang-ir-hlsl-legalize.h
  • source/slang/slang-ir-spirv-legalize.cpp
  • source/slang/slang-parameter-binding.cpp
  • tests/hlsl-intrinsic/ray-tracing/rt-pipeline-intrinsics-ahit.slang
  • tests/hlsl-intrinsic/ray-tracing/rt-pipeline-intrinsics-chit.slang
  • tests/hlsl-intrinsic/ray-tracing/rt-pipeline-intrinsics-int.slang
  • tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang

Comment thread source/slang/slang-ir-glsl-legalize.cpp Outdated
Comment thread tests/hlsl-intrinsic/ray-tracing/rt-pipeline-intrinsics-ahit.slang Outdated
Comment thread tests/hlsl-intrinsic/ray-tracing/rt-pipeline-intrinsics-chit.slang Outdated
Comment thread tests/hlsl-intrinsic/ray-tracing/rt-pipeline-intrinsics-int.slang Outdated
@jkwak-work jkwak-work marked this pull request as ready for review June 2, 2026 13:33
@jkwak-work jkwak-work requested a review from a team as a code owner June 2, 2026 13:33
@jkwak-work jkwak-work requested review from bmillsNV and removed request for a team June 2, 2026 13:33
github-actions[bot]

This comment was marked as outdated.

@jkwak-work

This comment has been minimized.

@coderabbitai

This comment has been minimized.

github-actions[bot]

This comment was marked as outdated.

@jkwak-work

This comment has been minimized.

@coderabbitai

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: dc284f9c-3c3f-4e6c-9851-02e3cd7b8f34

📥 Commits

Reviewing files that changed from the base of the PR and between 240a14a and 9d2552d.

📒 Files selected for processing (3)
  • tests/diagnostics/execution-model/sv-primitiveid-rt-invalid.slang
  • tests/hlsl-intrinsic/ray-tracing/rt-pipeline-intrinsics-int.slang
  • tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang

Comment thread tests/diagnostics/execution-model/sv-primitiveid-rt-invalid.slang Outdated
@jkwak-work

This comment has been minimized.

@jkwak-work

This comment has been minimized.

@coderabbitai

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
source/slang/slang-ir-legalize-varying-params.cpp (1)

821-841: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Nested mixed hit-input structs still bypass the PrimitiveID rewrite.

This classification only recurses through primitiveIDOnlyStructFields. A nested field like Inner { uint pid : SV_PrimitiveID; float2 bary : SV_Barycentrics; } is treated as ordinaryFields, so Line 840 returns false before any use-walking happens and inner.pid never reaches the new PrimitiveID substitution path.

Example: struct Outer { Inner inner; }; [shader("closesthit")] void main(Outer o) { use(o.inner.pid, o.inner.bary.x); } leaves the nested SV_PrimitiveID untouched.

Suggested fix: recurse into nested mixed structs as well and rebuild the surviving ordinary subtree at each level, or reject nested mixed carriers earlier with a diagnostic until that rewrite exists.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 57240942-3e40-42d9-be9c-bbc1950e55ea

📥 Commits

Reviewing files that changed from the base of the PR and between fbc972a and 968a0e6.

📒 Files selected for processing (3)
  • source/slang/slang-ir-legalize-varying-params.cpp
  • tests/hlsl-intrinsic/ray-tracing/rt-pipeline-intrinsics-chit.slang
  • tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang

@jkwak-work

Copy link
Copy Markdown
Collaborator Author

[Agent] Addressed the CodeRabbit outside-diff nested mixed struct finding in f0e623f. The PrimitiveID struct legalizer now analyzes nested structs recursively, narrows the surviving ordinary subtree at each level, rewrites nested PrimitiveID field accesses to the primitive-index intrinsic, and reconstructs original structs for whole nested forwards. Added HLSL/DXIL/GLSL/CUDA coverage for both direct nested mixed field access and forwarding input.inner to a helper. Validation: cmake --build --preset debug --target slangc slang-test; build/Debug/bin/slang-test tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang; build/Debug/bin/slang-test tests/hlsl-intrinsic/ray-tracing/rt-pipeline-intrinsics-chit.slang; git diff --check. ./extras/formatting.sh --modified could not run because gersemi, clang-format, prettier, and shfmt are not installed in PATH.

@jkwak-work

This comment has been minimized.

@coderabbitai

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
source/slang/slang-ir-legalize-varying-params.cpp (1)

1098-1128: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preflight all PrimitiveID replacements before narrowing nested field-access types.

This helper mutates fieldExtract/fieldAddress types at Line 1098 before it proves that every
SV_PrimitiveID field can be materialized. If emitRayTracingPrimitiveIndexValue() later returns
nullptr for one field, the function returns false at Lines 1116-1117 or Lines 1127-1128 after
already changing IR types, so the caller observes “legalization failed” with partially rewritten IR
still in the entry point.

Suggested fix
-    for (auto update : fieldAccessTypeUpdates)
-    {
-        update.inst->setFullType(
-            replaceParamValueType(builder, update.inst->getFullType(), update.valueType));
-    }
-
     List<IRStructField*> replacementFields;
     List<IRInst*> replacementValues;
     auto getPrimitiveIDValueReplacement = [&](IRStructField* field) -> IRInst*
     {
         for (Index i = 0; i < replacementFields.getCount(); i++)
@@
         replacementFields.add(field);
         replacementValues.add(valueReplacement);
         return valueReplacement;
     };
+
+    for (auto access : primitiveIDFieldAccesses)
+    {
+        if (!getPrimitiveIDValueReplacement(access.field))
+            return false;
+    }
+
+    for (auto update : fieldAccessTypeUpdates)
+    {
+        update.inst->setFullType(
+            replaceParamValueType(builder, update.inst->getFullType(), update.valueType));
+    }
 
     for (auto access : primitiveIDFieldAccesses)
     {
         auto valueReplacement = getPrimitiveIDValueReplacement(access.field);
         if (!valueReplacement)
♻️ Duplicate comments (1)
tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang (1)

35-42: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add direct SPIR-V coverage for the new nested-mixed entry points.

The new main_chit_struct_nested_mixed and main_chit_struct_nested_mixed_forward matrix omits
-target spirv-assembly, so the direct SPIR-V legalization path for these exact shapes is not
covered here.

Suggested test additions
+//TEST:SIMPLE(filecheck=STRUCT_NESTED_MIXED_SPIRV):-target spirv-assembly -entry main_chit_struct_nested_mixed -stage closesthit
+//TEST:SIMPLE(filecheck=STRUCT_NESTED_MIXED_FORWARD_SPIRV):-target spirv-assembly -entry main_chit_struct_nested_mixed_forward -stage closesthit

As per coding guidelines, tests should verify intended behavior and ensure new feature paths have corresponding coverage.

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 00de2de8-0763-4cf7-bf46-25441a712a48

📥 Commits

Reviewing files that changed from the base of the PR and between 968a0e6 and f0e623f.

📒 Files selected for processing (2)
  • source/slang/slang-ir-legalize-varying-params.cpp
  • tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang

Comment thread tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang
@jkwak-work

Copy link
Copy Markdown
Collaborator Author

[Agent] Addressed CodeRabbit’s PrimitiveID legalization preflight finding in 16800db. Field-access type rewrites now happen only after all PrimitiveID field replacements have been preflighted. I also tightened the CUDA checks for the nested mixed direct and forwarded cases. I left the duplicate direct-SPIR-V coverage request unchanged per the recorded reviewer directive to keep the new SV_PrimitiveID SPIR-V directives unqualified. Validation: cmake --build --preset debug --target slangc slang-test; build/Debug/bin/slang-test tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang; build/Debug/bin/slang-test tests/hlsl-intrinsic/ray-tracing/rt-pipeline-intrinsics-chit.slang; git diff --check. Formatting helper still cannot run here because gersemi, clang-format, prettier, and shfmt are missing.

@jkwak-work

This comment has been minimized.

@coderabbitai

This comment has been minimized.

github-actions[bot]

This comment was marked as outdated.

@jkwak-work

Copy link
Copy Markdown
Collaborator Author

[Agent] Addressed the latest automated review gap by extending the SV_PrimitiveID struct legalization to direct SPIR-V hit-stage entry points and adding unqualified SPIR-V test directives for the struct, nested struct, mixed struct, and forwarding cases. Validation: cmake --build --preset debug --target slangc slang-test, build/Debug/bin/slang-test tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang (43/43 passed, 13 ignored), and git diff --check. The repository formatter script could not run here because formatter binaries are not installed (clang-format, gersemi, prettier, shfmt).

@jkwak-work

This comment has been minimized.

@coderabbitai

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0dbe4b06-5107-4f0c-a639-9afb13b4ae65

📥 Commits

Reviewing files that changed from the base of the PR and between 16800db and 5d33c5c.

📒 Files selected for processing (4)
  • source/slang/slang-ir-glsl-legalize.cpp
  • source/slang/slang-ir-legalize-varying-params.cpp
  • source/slang/slang-ir-legalize-varying-params.h
  • tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang

Comment thread source/slang/slang-ir-glsl-legalize.cpp Outdated
@jkwak-work

This comment has been minimized.

@coderabbitai

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
source/slang/slang-ir-legalize-varying-params.h (1)

130-139: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🟡 Gap: valueEmitter parameter undocumented in function comment

The doc comment at lines 130-133 describes the struct-parameter rewriting behavior but does not explain the new optional valueEmitter parameter added at line 139. A caller cannot determine from the header:

  • What happens when valueEmitter is nullptr (default backend-agnostic emission?)
  • When a caller should provide a custom emitter (backend-specific primitive-index intrinsic?)
  • What the callback receives and must return

Suggestion: Extend the doc comment to document the valueEmitter parameter, e.g., add before line 134:

/// When `valueEmitter` is non-null, its callback is invoked for each primitive-ID
/// field to emit the replacement value; when null, default emission is used.

Source: Coding guidelines

source/slang/slang-ir-legalize-varying-params.cpp (1)

683-719: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Array-carried SV_PrimitiveID still bypasses this legalization.

This recursion only descends into direct IRStructType fields. A hit-stage input like struct Inner { uint pid : SV_PrimitiveID; }; struct Outer { Inner items[2]; }; falls through the ordinary-field branch here, so info->containsPrimitiveID stays false and tryLegalizeRayTracingPrimitiveIDStructParam() leaves the parameter untouched. That skips the PrimitiveID rewrite for items[i].pid and can leak an unsupported signature to later backend passes.

Suggested fix:

// Pseudocode
if (auto nestedStructType = as<IRStructType>(field->getFieldType()))
{
    ...
}
else if (auto arrayType = as<IRArrayTypeBase>(field->getFieldType()))
{
    // Recurse into the element type/layout when the element is a struct,
    // or diagnose explicitly if aggregate carriers are intentionally unsupported.
}

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 04110e8d-006a-46d2-b512-4fcc21e93462

📥 Commits

Reviewing files that changed from the base of the PR and between 16800db and dcd0acd.

📒 Files selected for processing (4)
  • source/slang/slang-ir-glsl-legalize.cpp
  • source/slang/slang-ir-legalize-varying-params.cpp
  • source/slang/slang-ir-legalize-varying-params.h
  • tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang

Comment thread source/slang/slang-ir-glsl-legalize.cpp
Comment thread source/slang/slang-ir-legalize-varying-params.h Outdated
@jkwak-work

This comment has been minimized.

@coderabbitai

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bc22e261-371f-4a53-9a65-52d9151adf2c

📥 Commits

Reviewing files that changed from the base of the PR and between dcd0acd and bd7a400.

📒 Files selected for processing (2)
  • source/slang/slang-ir-glsl-legalize.cpp
  • source/slang/slang-ir-legalize-varying-params.h

Comment thread source/slang/slang-ir-legalize-varying-params.h Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: ✅ Clean — no significant issues found

The PR plumbs SV_PrimitiveID through ray-tracing intersection/anyhit/closesthit on SPIR-V (direct + via-GLSL), DXIL/HLSL, and CUDA/OptiX. Unsupported backends (Metal, WGSL) are diagnosed at parameter-binding time with Diagnostics::Unimplemented and have a negative regression test. The IR rewrite uses traverseUses (snapshot semantics), guards against malformed input by failing the rewrite rather than producing null IR, and routes through a synthesized canonical helper __slang_ray_tracing_primitive_index that carries per-target intrinsic decorations.

Changes Overview

Semantic allowlist (core.meta.slang, slang-parameter-binding.cpp)

  • Adds [require(intersection|anyhit|closesthit)] to the sv_primitiveid get accessor.
  • Carves SV_PrimitiveID out of the "no in parameters" rule for intersection/raygen/miss/callable and out of the "in is hit attributes" rule for anyhit/closesthit. For Metal/WGSL the carve-out emits Diagnostics::Unimplemented instead of accepting the input.

HLSL/DXIL legalization (slang-emit.cpp, slang-ir-hlsl-legalize.{cpp,h}, slang-ir-legalize-varying-params.{cpp,h})

  • Renames legalizeNonStructParameterToStructForHLSLlegalizeParametersForHLSL; the renamed pass now also calls legalizeRayTracingPrimitiveIDParamsForHLSL, which uses a new HLSLRayTracingPrimitiveIDParamLegalizeContext : EntryPointVaryingParamLegalizeContext to rewrite hit-stage SV_PrimitiveID parameters and struct fields to calls of the synthesized __slang_ray_tracing_primitive_index helper.
  • Pass placement preserves the original "must run before existential layout" invariant.

Shared rewrite core (slang-ir-legalize-varying-params.cpp)

  • New tryLegalizeRayTracingPrimitiveIDParam and tryLegalizeRayTracingPrimitiveIDStructParam handle both the flat uint pid : SV_PrimitiveID and the nested-struct-field form, including mixed-content structs (where the struct is narrowed to its remaining ordinary fields).
  • New RayTracingPrimitiveIDValueEmitter indirection lets a backend (currently SPIR-V direct) substitute its own emitter for the field-replacement value.

SPIR-V (slang-ir-glsl-legalize.cpp, slang-ir-spirv-legalize.cpp)

  • consolidateRayTracingParameters now optionally pre-rewrites hit-stage SV_PrimitiveID before consolidation. Direct SPIR-V uses DirectSPIRVPrimitiveIDEmitterContext to emit a BuiltinInput global param + load instead of routing through gl_PrimitiveID.
  • slang-ir-spirv-legalize.cpp flips the address space of an sv_primitiveid system-value var to BuiltinInput for hit stages.

CUDA/OptiX (slang-ir-legalize-varying-params.cpp)

  • CUDAEntryPointVaryingParamLegalizeContext calls the shared rewriters in processParam and adds a SystemValueSemanticName::PrimitiveID case that emits optixGetPrimitiveIndex() via the synthesized helper.

Multi-entry-point support (slang-ir-legalize-varying-params.cpp)

  • processModule now collects entry points before processing and adds a shouldProcessEntryPoint virtual hook so target-specific contexts can filter (the new HLSL context only processes hit stages).

Tests (6 files, ~817 added lines)

  • tests/hlsl-intrinsic/ray-tracing/sv-primitiveid-raytracing.slang (523 lines) covers all 5 backends across all 3 hit stages, plus int/uint, used/unused, name-collision with the synthesized helper, inout-style mutation, struct-wrapped, nested-struct, and mixed-content-struct forms.
  • tests/diagnostics/execution-model/sv-primitiveid-rt-invalid.slang covers raygen/miss/callable rejection, inout/out rejection on hit stages, the Metal/WGSL "Unimplemented" diagnostic, and bad-type rejection.
  • tests/cuda/sv-primitiveid-raytracing.slang adds a focused CUDA closesthit case.
  • rt-pipeline-intrinsics-{ahit,chit,int}.slang get new SVPID entry points checked against SPIR-V BuiltIn PrimitiveId and DXIL dx.op.primitiveIndex.i32.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CoPilot pr: non-breaking PRs without breaking changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slang does not accept SV_PrimitiveID as input to intersection shaders

2 participants